Potete trovare questa lezione (ed altre) sul mio sito github:
https://github.com/EnricoGiampieri/lezionipython
un ottimo tutorial online lo potete trovare alla pagina:
Il Python è un linguaggio interpretato di alto livello.
Questa è una maniera complicata per dire che evita moltissimi dei dolori della programmazione classica: il fatto che sia interpretato significa che non sono necessari step di compilazione, rendendo più semplice il ciclo sviluppo - esecuzione - correzione
Python ha come principale linea guida il concetto di leggibilità, cercando il più possibile di rendere semplice agli sviluppatori scrivere librerie semplici ed intuitive.
Questo permette di utilizzare soltanto python per sviluppare i prototipi del codice fino ad arrivare al codice di produzione, semplificando e velocizzando l'intero processo che parte dall'idea che si vuole implementare fino ad ottenere il risultato finale.
Python supporta di base tutte le operazioni matematiche più comuni, compreso il supporto per la matematica complessa, e tutti i costrutti più comuni di programmazione (e molti altri) come:
Permette inoltre di programmare con molti approcci diversi:
Faremo una breve introduzione alla programmazione in pyhton, senza entrare nel dettaglio delle caratteristiche del linguaggio, introducendo quindi solo una parte delle possibilità offerte da questo linguaggio e dalle sue librerie.
Conoscere un minimo di python e delle sue librerie di calcolo numerico ci permetterà di toccare con mano molti dei problemi che affronteremo lungo il corso.
Esistono molti modi diversi di lavorare tramite Python.
Il fondamentale è tramite la shell di python, un terminale che esegue le righe di comando mano a mano che vengono inserite, ed è estremamente utile per testare il codice al volo prima di inserirlo dentro un programma. Il terminale di python si può lanciare da terminale digitando python.
>>> Dimostrazione
Il secondo metodo è scrivere uno (o più) script contenente i comandi che si vogliono eseguire, e farlo eseguire da python come un programma qualsiasi tramite il comando
python nomedelfile.py.
Le cose più interessanti di trovano però andando a cercare fra i vari programmi disponibili.
Uno degli editor più famosi per il calcolo scientifico in python è Spyder (http://code.google.com/p/spyderlib/), che fornisce un'interfaccia molto simile a quella di Matlab. È unprogramma molto solido e funzionale, ed è un'ottima piattaforma su cui lavorare.
Un'altro approccio è l'utilizzo di un IDE (Integrated Development Environment) completo, quale PyCharm, Wing o Eclipse. Il mio personale preferito, molto più semplice ma con tutte le funzioni che mi servono è Ninja (http://ninja-ide.org/).
Fra tutti lo strumento però in assoluto più potente è sicuramente Jupyter (http://jupyter.org/). Jupyter fornisce tre programmi:
Python arriva di base installato con un gran numero di librerie sia sotto linux che sotto macOSX, mentre invece và installato da zero su windows.
Installare nuove librerie è molto semplice sfruttando il programma pip, che permette di dire a python quale libreria si desidera e lui la scaricherà ed installerà sul sistema. Il programma è a riga di comando e quasi tutte le librerie numeriche richiedono però la presenza di un compilatore, quindi potrebbe non essere comodo per chi non è abituato a lavorare da terminale.
Una comoda alternativa sono le librerie all-inclusive. Queste sono normalmente a pagamento, ma arrivano con python e tantissime librerie preinstallate e configurate per il sistema in uso. Fra le principali ci sono:
Se invece non volete installarlo nel vostro computer ma solo provarlo online (tipicamente sono piani a pagamento o gratuiti in modo ristretto):
se volete tenervi aggiornati sulle novità del mondo Python, due buone newletters sono:
Andremo a visualizzare parte del nostro codice anche sul sito Python Tutor, che ci aiuterà a capire cosa sta succedendo
print("not Hello, World!")
not Hello, World!
Ok, questo era facile. Possiamo usare la funzione print per stampare (quasi) qualsiasi cosa:intanto lo usiamo per vedere i risultati di alcune operazioni matematiche
print(1)
print(1 + 2)
print((4 + 5j) * (2 + 3j))
print(4 ** 4)
1 3 (-7+22j) 256
Nelle vecchie versioni di Python (2.7 o inferiori) la divisione fra numeri interi restituiva un intero (come in C). Nella nuova versione (python 3, quello che utilizzeremo per queste lezioni) questo comportamento è stato modificato, ed ora la divisione fra numeri restituisce il valore decimale come ci si attenderebbe
2 / 3
0.6666666666666666
Per avere la divisione intera si utilizza un operatore specifico, usando il doppio segno di divisione.
2 // 3
0
Per ottenere le stesso comportamento nelle vecchie versioni si può utilizzare il comando:
from __future__ import division
Per utilizzare funzioni matematiche più avanzate abbiamo bisogno di utilizzare una delle librerie che arrivano con python, la libreria math, che ci mette a disposizione una lunga lista di funzioni. per utilizzare math basta scrivere
import math
There's an app for that!
Ed ora abbiamo accesso a tutte le funzioni necessarie. Se avessimo bisogno di lavorare con i numeri complessi, esiste una libreria gemella chiamata cmath.
Per avere più informazioni sulla libreria che andiamo ad usare possiamo utilizzare due comandi molto utili, dir per sapere quali siano le sue funzioni, ed help per averne una descrizione. Visto che il risultato di help(math) è piuttosto lungo, eviterò di mostrarlo.
print(dir(math))
['__doc__', '__file__', '__loader__', '__name__', '__package__', '__spec__', 'acos', 'acosh', 'asin', 'asinh', 'atan', 'atan2', 'atanh', 'ceil', 'copysign', 'cos', 'cosh', 'degrees', 'e', 'erf', 'erfc', 'exp', 'expm1', 'fabs', 'factorial', 'floor', 'fmod', 'frexp', 'fsum', 'gamma', 'gcd', 'hypot', 'inf', 'isclose', 'isfinite', 'isinf', 'isnan', 'ldexp', 'lgamma', 'log', 'log10', 'log1p', 'log2', 'modf', 'nan', 'pi', 'pow', 'radians', 'sin', 'sinh', 'sqrt', 'tan', 'tanh', 'tau', 'trunc']
dir mi ritorna una lista con i nomi di tutte le funzioni presenti dento math. Per usarle basta scrivere
nomelibreria.nomefunzione
math.exp(1)
2.718281828459045
Se voglio sapere cosa faccia di preciso una di quelle funzioni basta usare la funzione help
help(math.log1p)
Help on built-in function log1p in module math: log1p(...) log1p(x) Return the natural logarithm of 1+x (base e). The result is computed in a way which is accurate for x near zero.
print(math.pi)
print(math.log1p(math.pi))
3.141592653589793 1.4210804127942926
math.log( math.pi + 1.0 )
1.4210804127942926
Se avete bisogno di poche funzioni e non volete digitare ogni volta il nome della libreria potete importare solo una parte dei nomi, che saranno poi disponibili senza bisogno di fare riferimenti alla librerie.
from math import radians, log1p, modf
print(log1p(1.0))
0.6931471805599453
Potreste trovare alcuni tutorial su internet che propongono di importare le funzioni da una libreria con il seguente comando:
from math import *
Evitatelo come la peste.
Questo comando importa infatti tutti i nomi di funzioni dalla libreria, sovrascrivendo possibili funzioni già esistenti. Questo comportamento potrebbe riservarvi delle sorprese molto spiacevoli, e di cui è difficile rendersi conto!
Inclusi nel linguaggio di base arrivano anche molte strutture dati estremanente utili. Una lista non esaustiva include:
Una menzione particolare la meritano i dizionari, che permettono di memorizzare dei dati in modalità random (ovvero non sequenziale) accedendovi tramite nomi esplicativi
rubrica = dict()
rubrica['Ludovico Fabbri'] = ('334-5678901',
'Via Larga 34, Bo')
print(rubrica['Ludovico Fabbri'])
('334-5678901', 'Via Larga 34, Bo')
Se provo a cercare un elemento assente, Python si lamenta in modo rumoroso.
Questo è un design intenzionale, meglio fallire presto in modo chiaro che non dare risultati inaspettati!
rubrica['enrico giampieri']
--------------------------------------------------------------------------- KeyError Traceback (most recent call last) <ipython-input-48-353ef568a7d1> in <module>() ----> 1 rubrica['enrico giampieri'] KeyError: 'enrico giampieri'
try:
print(rubrica['enrico giampieri'])
except KeyError:
print("non trovato")
non trovato
È possibile definire le proprie funzioni tramite il comando def. In questo caso creerò una funzione che prende due oggetti e ne restituisce la somma.
A python non interessa di che oggetti di tratti, fintantochè sia definita fra di loro una somma. Posso usare questa funzione per sommare indifferentemente fra di loro numeri, stringhe, liste o distribuzioni di probabilità.
def mia_funzione(a, b):
return a+b
print(mia_funzione(1, 2))
print(mia_funzione('hello ', 'world!'))
print(mia_funzione([1, 2, 3], [4, 5, 6]))
3 hello world! [1, 2, 3, 4, 5, 6]
Python supporta le iterazioni sia con il costrutto while che con il for. Il for in pyhton è un ciclo speciale estremamente potente, ed è quindi il modo principale di scrivere cicli.
Nel classico modo di scrivere cicli, per scorrere una lista di oggetti devo fare un ciclo sopra gli indici della lista, stando attento a trovare bene i bordi, e poi operare sul mio oggetto. Prendiamo ad esempio il caso di voler stampare tutto il contenuto di una lista.
lista_ingredienti = ['pane', 'pomodori', 'farina', 'acqua', 'sale', 'mozzarella']
lunghezza = len(lista_ingredienti)
idx = 0
while idx < lunghezza:
print(lista_ingredienti[idx])
idx += 1
Due delle linee di questo codice (trovare la lunghezza della lista e ricavarne l'elemento) sono sempre presenti. Per ovviare a queste linee superflue, il python permette di usare il ciclo for per scorrere direttamente gli elementi della lista
lista_ingredienti = ("acqua", "farina")
for ingrediente in lista_ingredienti:
print(ingrediente)
acqua farina
una funzione usata molto comunemente all'interno dei cicli è la funzione zip, che serve per fare il ciclo contemporaneamente su due liste/stringhe allo stesso momento.
nome = 'enrico'
for ch1, ch2 in zip(nome, nome[1:]):
print(ch1, ch2)
e n n r r i i c c o
Se voglio leggere un file ho a disposizione la funzione open
.
Questa funzione può essere usata per delimitare un blocco di codice all'interno del quale il file è aperto. Al termine delle operazioni, questo verrò chiuso in modo automatico e sicuro, evitando che rimanga aperto e venga corrotto da altri processi
%%file prova.txt
tonno
mandibola
rum
pinocchio
sigmoide
Writing prova.txt
with open('prova.txt') as file: #commento
for line in file:
print(repr(line))
print(len(line))
'tonno\n' 6 'mandibola\n' 10 'rum\n' 4 'pinocchio\n' 10 'sigmoide' 8
import this
The Zen of Python, by Tim Peters Beautiful is better than ugly. Explicit is better than implicit. Simple is better than complex. Complex is better than complicated. Flat is better than nested. Sparse is better than dense. Readability counts. Special cases aren't special enough to break the rules. Although practicality beats purity. Errors should never pass silently. Unless explicitly silenced. In the face of ambiguity, refuse the temptation to guess. There should be one-- and preferably only one --obvious way to do it. Although that way may not be obvious at first unless you're Dutch. Now is better than never. Although never is often better than *right* now. If the implementation is hard to explain, it's a bad idea. If the implementation is easy to explain, it may be a good idea. Namespaces are one honking great idea -- let's do more of those!
Proviamo a sviluppare un semplice automa cellulare, basato sui metodi delinieati da Wolfram.
Il nostro sistema è una stringa di bit uno e zero, con delle regole di evoluzione basate sullo stato del bit e dei suoi vicini.
Useremo la regola 30, ispirato da questo blog
rule30 = {"000": ' ',
"00 ": ' ',
"0 0": ' ',
" ": ' ',
"0 ": '0',
" 00": '0',
" 0 ": '0',
" 0": '0',
}
stato = ' 0 '
result = []
for a,b,c in zip(stato[:-2], stato[1:-1], stato[2:]):
abc = a+b+c
r = rule30[abc]
result.append(r)
print(''.join(result))
000
len(stato), len(result)
(41, 39)
def avanza(stato, regola):
risultato = []
stato = ' '+stato+' '
for a,b,c in zip(stato[:-2], stato[1:-1], stato[2:]):
abc = a+b+c
r = rule[abc]
risultato.append(r)
return ''.join(risultato)
avanza(stato, rule30)
' 000 '
iniziale = ' 0 '
stato = iniziale
for i in range(50):
print(stato.replace('0', '\u2588'))
stato = avanza(stato, rule30)
█ ███ ██ █ ██ ████ ██ █ █ ██ ████ ███ ██ █ █ █ ██ ████ ██████ ██ █ ███ █ ██ ████ ██ █ ███ ██ █ █ ████ ██ █ ██ ████ ██ █ █ ████ ██ █ ███ ██ ██ █ █ ██ ████ ██ ███ ███ ██ ███ ██ █ █ ███ █ ███ █ █ ██ ████ ██ █ █ █████ ███████ ██ █ ███ ████ █ ███ █ ██ ████ ██ ███ ██ ██ █ ███ ██ █ █ ███ █ ██ ███ ████ ██ █ ██ ████ ██ █ ██████ █ █ ███ ████ ██ █ ███ ████ ████ ███ ██ █ █ █ ████ ██ ███ █ ██ █ █ █ ███ ██ █ █ █ ███ █ ███ ██ █ ███ ██ █ █ █ █ ██ ██ █ ███ █ █ ████ █ █ ██ ███ █ █ ███ ████ ██ █████ █ █████ █ █ █ █ █ ███ █ ██ █ █ ██ █ █████ █ █ ████ █ ██ █ ████ ██ █ ██ ██ █ █ █ █ ███ █ █ █ ███ ████ █ ██ █ ██ █ █ ██ ██ ████ ██ ██ ███ █ █ ████ █ █ █ █ █ ██ █ █ ███ █ ██ ████ █ █ █ ████ █ █ █ █████ █ ██████ █ █ ██ █ █ █ █ █ ████ ████ ████ ██ █ █ █ ██ ██ █ █ █ ██ █ ██ █ ██ █ █ █ ███ █ ██ ███ ██ █ ███ ██ █ █████ █ █ █ █ ███ █ █ █ █ █ █ ████ █ █ █ █ ████ █████ █████ ██ █████ █ ██ █ █ █ █ █ ██ █ █ █ █ █████ █ █ █ ██ ██ █ █ ███ ██████ ██ █ █ █ █ █ █ █ █ ██ ██ █ ██ ███ ██ ██ █ █ █ ███████ █ █ ███ █ █ ██ ███ ███ █ █ █ █ ████ █ █ ██ ██ ███ █ █ █ █ █ ██ ██ ██ ██ █ █ █ █ █████ █ █ █ █ █ ██ █ ██ █ ██████████ █ █ █ █ █ ██ ██ ████ ██████ ██ █ █ █ █ █ █ ███ █ █ ██ █ █ █ █ █ ████ █ █ ███ ███ ██ ██ █ █ █ █ █ ███████ █ ██ █ ██ ███ █ █ █ █ █ ██ ██ ███ █ ████ ██ █ █ █ █ █ █ █ ███ █ ██ █ █ ███ ████ ██ █ █ █ █ █ █ ██ ██ █ ██ ██ ██ █ █
def avanza(stato, regola, bordo='circolare'):
risultato = []
if bordo=='circolare':
stato = stato[-1]+stato+stato[0]
elif bordo=='riflettente':
stato = stato[0]+stato+stato[-1]
else:
stato = borso+stato+bordo
for a,b,c in zip(stato[:-2], stato[1:-1], stato[2:]):
abc = a+b+c
r = rule[abc]
risultato.append(r)
return ''.join(risultato)
iniziale = ' 0 '
stato = iniziale
for i in range(50):
print(stato.replace('0', '\u2588'))
stato = avanza(stato, rule30)
█ ███ ██ █ ██ ████ ██ █ █ ██ ████ ███ ██ █ █ █ ██ ████ ██████ ██ █ ███ █ ██ ████ ██ █ ███ ██ █ █ ████ ██ █ ██ ████ ██ █ █ ████ ██ █ ███ ██ ██ █ █ ██ ████ ██ ███ ███ ██ ███ ██ █ █ ███ █ ███ █ █ ██ ████ ██ █ █ █████ ███████ ██ █ ███ ████ █ ███ █ ██ ████ ██ ███ ██ ██ █ ███ ██ █ █ ███ █ ██ ███ ████ ██ █ ██ ████ ██ █ ██████ █ █ ███ ████ ██ █ ███ ████ ████ ███ ██ █ █ ████ ██ ███ █ ██ █ █ █ ███ ██ ███ █ ███ █ ███ ██ █ ███ ██ █ █ █ █ █ ██ █ ███ █ █ ████ █ █ ██ ██ ███████ ████ ██ █████ █ █████ █ █ █ ███ █ ██ █ █ ██ █ ██████ █ ██ █ ██ █ ████ ██ █ ██ ██ ███ ██ ███ █ █ █ ███ ████ █ ██ █ █ ███ █ ████ ██ ██ ███ █ █ ██ █ ███ ████ ██ █ █ ███ █ ██ ████ ███ █ ███ █ █ █████ █ ██████ █ █ █████ █ ██ ████ ████ ████ ███ █ ██████ █ █ ██ █ ██ ███ ██ ██ ████ ███ ██ █ ███ ██ █ ██ █ █ ███ █ ██ █ █ █ █ █ █ █ ███ █ ███ ██ ██ █ ███ █████ ██ █████ █ █ █ █ ██ █ ████ █ █ █ █ ██ ██ █ ██ █ ██████ █ ███ ██████ ██ █ █ █ █ █ █ █ ██ █ █ ██ █ ██ ████ █ ████ ██ ██ █ ████ █ █ ██ █ ███ █ █ █ █ ██ ████ █ ██ ██ █ █ █ █ ██ ██ █ █ ███ █ ██ █ █ ███ ███████ ███ ███ █ █ █ █ █████ ████ █ █ █ █ ███ █ ████ █ ███ ██ ███ █ █ █████ █ █ ██ ██ █ ██ █ █ ██ █ █ █ ██ ██ ██ ███ ██████ █████████ ██ ██ ██ █ █ ███ █ █ █ █ █ ███ ████ █ ████ ███ ███ ██ █ ██ █ ███ ████ █ █ ██ █ ██ █ █ ████ █ ██ █ ████████ ████ ██
def avanza(stato, regola, bordo='circolare'):
if bordo=='circolare':
stato = stato[-1] + stato + stato[0]
elif bordo=='riflettente':
stato = stato[0] + stato + stato[-1]
else:
stato = bordo[0] + stato + bordo[0]
space = zip(stato[:-2], stato[1:-1], stato[2:])
risultato = [rule[a+b+c] for a,b,c in space]
return ''.join(risultato)
iniziale = ' 0 '
stato = iniziale
for i in range(50):
print(stato.replace('0', '\u2588'))
stato = avanza(stato, rule30, bordo='riflettente')
█ ███ ██ █ ██ ████ ██ █ █ ██ ████ ███ ██ █ █ █ ██ ████ ██████ ██ █ ███ █ ██ ████ ██ █ ███ ██ █ █ ████ ██ █ ██ ████ ██ █ █ ████ ██ █ ███ ██ ██ █ █ ██ ████ ██ ███ ███ ██ ███ ██ █ █ ███ █ ███ █ █ ██ ████ ██ █ █ █████ ███████ ██ █ ███ ████ █ ███ █ ██ ████ ██ ███ ██ ██ █ ███ ██ █ █ ███ █ ██ ███ ████ ██ █ ██ ████ ██ █ ██████ █ █ ███ ████ ██ █ ███ ████ ████ ███ ██ █ █ ████ ██ ███ █ ██ █ █ █ ███ ██ ██ █ ███ █ ███ ██ █ ███ ██ █ █ █ ██ █ ██ █ ███ █ █ ████ █ █ ██ ███ ████ ████ ██ █████ █ █████ █ █ ██ ███ █ ██ █ █ ██ █ █████ ██ █ ██ █ ██ █ ████ ██ █ ██ ██ █ ██ █ █ ███ █ █ █ ███ ████ █ ██ █ ██ ███ █ █ ████ ██ ██ ███ █ █ ████ ██ █ ██ ██ █ █ ███ █ ██ ████ █ ██ █ ██ █ █ █ █████ █ ██████ █ █ ██ █ █ ████ ████ ████ ████ ██ █ ██ ████ █ █ ██ █ ██ █ ██ ██ █ █ ███ ███ ██ █ ███ ██ █ █████ ██ ████ █████ █ █ █ █ █ ████ █ █ █ █ ███ █████ ██ █████ █ ██ ███ ███ ██ █ █ █ █ █ █████ ██ ███ ███ ██ ███ ██████ ██ █ █ ██ ███ ███ ███ █ █ ██ ███ ██ ██ █ ███ ███ ██████ █ █ ██ ███ ███ █████ ███ ███ █ ██ ██ ███ █ █ ██ ███ ███ █ ██ █ █ █ █ █████ ██ █ ██ ███ ████ ██ ██████████ █ ████ ███ ███ ███ ███ ██ ██ █ ███ █ ██ █ █ ██ █ ██ █ █████ ███ █ █ ██████ ██ ██ ██ ████ ███ █ █ █ █ ██ ███ █ ███ █ ██ █ ██ █ ██ ███ ██ █ █ ██ █ █████ ███ █ █ █ █ ██ ███ ████ ██ ██ ███ █ █ ████ █ █ █ ███ █ █
RULES = {30: {"111": '0', "110": '0', "101": '0', "000": '0',
"100": '1', "011": '1', "010": '1', "001": '1'},
90: {"111": "0", "110": "1", "101": "0", "100": "1",
"011": "1", "010": "0", "001": "1", "000": "0"},
110: {"111": '0', "110": '1', "101": '1', "100": '0',
"011": '1', "010": '1', "001": '1', "000": '0'},
184: {"111": "1", "110": "0", "101": "1", "100": "1",
"011": "1", "010": "0", "001": "0", "000": "0"}
}